/**
 * 
 */
package v1c14;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @author gjunming@gmail.com
 * @version Aug 17, 2009 1:46:01 PM
 */
public class ThreadTest {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {

			@Override
			public void run() {
				ThreadFrame threadFrame = new ThreadFrame();
				threadFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				threadFrame.setVisible(true);
			}
		});

	}
}

class ThreadFrame extends JFrame {
	private static final int FWIDTH = 300;
	private static final int FHEIGHT = 200;

	BallComponent ballComp;
	private BallRunable ballRunable;

	public ThreadFrame() {
		// add buttons and button panel;
		JPanel buttonPanel = new JPanel();

		ballComp = new BallComponent();
		add(ballComp, BorderLayout.CENTER);

		addButton(buttonPanel, "Start", new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				addBall();
			}
		});
		addButton(buttonPanel, "Close", new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		setSize(FWIDTH, FHEIGHT);
		add(buttonPanel, BorderLayout.SOUTH);
	}

	// the button generator
	public void addButton(JPanel bPanel, String bValue, ActionListener listener) {
		JButton newButton = new JButton(bValue);
		bPanel.add(newButton);
		newButton.addActionListener(listener);
	}

	// add ball and left it run 1000 times
	public void addBall() {

		Ball ball = new Ball();
		ballComp.add(ball);
		ballRunable = new BallRunable(ball, ballComp);
		Thread r = new Thread(ballRunable);
		r.start();
	}
}

class Ball {
	private static final double XSIZE = 10;
	private static final double YSIZE = 10;
	private double x;
	private double y;
	private double dx = 1;
	private double dy = 1;

	public void move(Rectangle2D bounds) {
		x += dx;
		y += dy;
		if ((x > bounds.getMaxX()) || (x < bounds.getMinX())) {
			dx = -dx;
		}

		if ((y > bounds.getMaxY()) || (y < bounds.getMinY())) {
			dy = -dy;
		}

	}

	public Ellipse2D getSharp() {
		return new Ellipse2D.Double(x, y, XSIZE, YSIZE);
	}
}

class BallComponent extends JPanel {
	private final ArrayList<Ball> Balls = new ArrayList<Ball>();

	public void add(Ball b) {
		Balls.add(b);
	}

	public void paintCom(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;
		for (Ball b : Balls) {
			g2d.fill(b.getSharp());
		}
	}
}

class BallRunable implements Runnable {
	private static final int STEPS = 10000;
	private static final long DELAY = 1;
	private final Ball ball;
	private final BallComponent ballComp;

	public BallRunable(Ball ball, BallComponent ballComp) {
		this.ball = ball;
		this.ballComp = ballComp;
	}

	/*
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		try {
			for (int i = 1; i <= STEPS; i++) {
				ball.move(ballComp.getBounds());
				ballComp.paintCom(ballComp.getGraphics());

				Thread.sleep(DELAY);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
